﻿using System;
using System.Collections;
using System.Collections.Generic;
using Autodesk.Revit.DB;
using YJKRevitBase.Math;

namespace YJKRevitKernel.ElementSearchUtility.LinkDocumentSuite
{
	public class FilteredElementCollectorLinkDocument : IEnumerable<BaseLinkDocumentResultBean>, IEnumerable
	{
		public FilteredElementCollectorLinkDocument AddViewLimit(BoundingBoxContainsPointFilter input)
		{
            this.AddViewLimit_Single(input);
			return this;
		}

		public FilteredElementCollectorLinkDocument AddViewLimit(BoundingBoxIntersectsFilter input)
		{
            this.AddViewLimit_Single(input);
			return this;
		}

		public FilteredElementCollectorLinkDocument AddViewLimit(BoundingBoxIsInsideFilter input)
		{
            this.AddViewLimit_Single(input);
			return this;
		}

		public FilteredElementCollectorLinkDocument AddViewLimit(ElementIntersectsSolidFilter input)
		{
            this.AddViewLimit_Single(input);
			return this;
		}

		public FilteredElementCollectorLinkDocument AddCustomLimit(CustomGetElementFilter inputDelegate)
		{
			this.m_GetElementFilterDelegate = inputDelegate;
			this.FilterByCoreFilter();
			return this;
		}

		public FilteredElementCollectorLinkDocument OfCategory(BuiltInCategory inputCategory)
		{
			ElementCategoryFilter filter = new ElementCategoryFilter(inputCategory);
			this.WherePass(filter);
			return this;
		}

		public FilteredElementCollectorLinkDocument OfCalss(Type inputType)
		{
			if (null != inputType)
			{
				ElementClassFilter filter = new ElementClassFilter(inputType);
				this.WherePass(filter);
				return this;
			}
			throw new System.ArgumentNullException();
		}

		public FilteredElementCollectorLinkDocument WhereElementIsElementType()
		{
			ElementIsElementTypeFilter filter = new ElementIsElementTypeFilter(false);
			this.WherePass(filter);
			return this;
		}

		public FilteredElementCollectorLinkDocument WhereElementIsNotElementType()
		{
			ElementIsElementTypeFilter filter = new ElementIsElementTypeFilter(true);
			this.WherePass(filter);
			return this;
		}

		public FilteredElementCollectorLinkDocument WherePass(ElementFilter filter)
		{
			if (filter != null)
			{
				this.AddOneElementFilter(filter);
				this.FilterBean(this.m_coreFilter);
				return this;
			}
			throw new System.ArgumentNullException();
		}

		public FilteredElementCollectorLinkDocument SetLevelLimit(Level limitLevel, double useTolerance = 0.0)
		{
			if (limitLevel == null)
			{
				throw new System.ArgumentNullException();
			}
			return this.SetLevelLimit(limitLevel.Elevation, useTolerance);
		}

		public FilteredElementCollectorLinkDocument SetLevelLimit(double useLevelLimit, double useTolerance = 0.0)
		{
			this.m_bIfUseLevelLimit = true;
			this.m_dUseLevelLimit = useLevelLimit;
			this.m_dUesLevelLimitTolerance = useTolerance;
			if (this.m_coreFilter != null)
			{
				this.FilterBean(this.m_coreFilter);
			}
			return this;
		}

		public FilteredElementCollectorLinkDocument(Autodesk.Revit.DB.Document inputDoc)
		{
			this.m_useDoc = inputDoc;
		}

		public List<BaseLinkDocumentResultBean> GetAllElement()
		{
			List<BaseLinkDocumentResultBean> lstResultBean = this.m_lstResultBean;
			this.m_lstResultBean = null;
			this.FilterBean(this.m_getAllElementFilter);
			List<BaseLinkDocumentResultBean> lstResultBean2 = this.m_lstResultBean;
			this.m_lstResultBean = lstResultBean;
			return lstResultBean2;
		}

		public IEnumerator<BaseLinkDocumentResultBean> GetEnumerator()
		{
			if (this.m_lstResultBean != null)
			{
				return this.m_lstResultBean.GetEnumerator();
			}
			return new List<BaseLinkDocumentResultBean>().GetEnumerator();
		}

		public List<BaseLinkDocumentResultBean> ToBeans()
		{
			if (this.m_lstResultBean != null)
			{
				return this.m_lstResultBean;
			}
			return new List<BaseLinkDocumentResultBean>();
		}

		IEnumerator IEnumerable.GetEnumerator()
		{
			if (this.m_lstResultBean != null)
			{
				return this.m_lstResultBean.GetEnumerator();
			}
			return new List<BaseLinkDocumentResultBean>().GetEnumerator();
		}

		private List<BaseLinkDocumentResultBean> FilterBeanByLevelLimit(List<BaseLinkDocumentResultBean> inputLst, double inputdLevelLimit, double inputdLevelLimitTolerance)
		{
			if (inputLst == null)
			{
				return new List<BaseLinkDocumentResultBean>();
			}
			List<BaseLinkDocumentResultBean> list = new List<BaseLinkDocumentResultBean>();
			foreach (BaseLinkDocumentResultBean baseLinkDocumentResultBean in inputLst)
			{
				Transform totalTransform = baseLinkDocumentResultBean.GetTotalTransform();
				BoundingBoxXYZ boundingBoxXYZ = baseLinkDocumentResultBean.UseElement.get_BoundingBox(null);
				if (boundingBoxXYZ == null)
				{
					Level aelementLevel = this.GetAElementLevel(baseLinkDocumentResultBean.UseElement);
					if (aelementLevel != null && MathUtility.IsEqual(aelementLevel.Elevation + LinkDocumentUtility.CalculateTransformEffectOnZ(totalTransform), inputdLevelLimit, inputdLevelLimitTolerance))
					{
						list.Add(baseLinkDocumentResultBean);
					}
				}
				else
				{
					double z = boundingBoxXYZ.Max.Z;
					double num = boundingBoxXYZ.Min.Z;
					double val = z + LinkDocumentUtility.CalculateTransformEffectOnZ(totalTransform);
					num += LinkDocumentUtility.CalculateTransformEffectOnZ(totalTransform);
					if (!MathUtility.LessThan(val, inputdLevelLimit, inputdLevelLimitTolerance) && !MathUtility.LessThan(inputdLevelLimit, num, inputdLevelLimitTolerance))
					{
						list.Add(baseLinkDocumentResultBean);
					}
				}
			}
			return list;
		}

		private void AddViewLimit_Single(ElementFilter input)
		{
			this.m_lstViewLimitFilter.Add(input);
			this.FilterByCoreFilter();
		}

		private void FilterByCoreFilter()
		{
			if (this.m_coreFilter != null)
			{
				this.FilterBean(this.m_coreFilter);
			}
		}

		private void AddOneElementFilter(ElementFilter input)
		{
			if (this.m_coreFilter == null)
			{
				this.m_coreFilter = input;
				return;
			}
			LogicalAndFilter coreFilter = new LogicalAndFilter(this.m_coreFilter, input);
			this.m_coreFilter = coreFilter;
		}

		private void FilterBean(ElementFilter inputFilter)
		{
			if (inputFilter == null)
			{
				return;
			}
			List<ElementFilterPacker> list = new List<ElementFilterPacker>();
			list.Add(new ElementFilterPacker(inputFilter, false));
			foreach (ElementFilter input in this.m_lstViewLimitFilter)
			{
				list.Add(new ElementFilterPacker(input, true));
			}
			ViewTransformFilterBean inputViewFilter = new ViewTransformFilterBean(list, null, this.m_GetElementFilterDelegate);
			FilterLimitBean filterLimitBean = new FilterLimitBean(inputFilter, inputViewFilter, null);
			if (this.m_lstResultBean == null)
			{
				this.m_lstResultBean = LinkDocumentUtility.SearchElementUseDelegate(this.m_useDoc, filterLimitBean, new GetElementDelegate(this.GetElementByFilter), false);
				return;
			}
			List<BaseLinkDocumentResultBean> list2 = new List<BaseLinkDocumentResultBean>();
			foreach (BaseLinkDocumentResultBean baseLinkDocumentResultBean in this.m_lstResultBean)
			{
				ElementFilter useFilter;
				if (filterLimitBean.IfViewLimit())
				{
					Transform transform = baseLinkDocumentResultBean.GetTotalTransform();
					if (transform != null)
					{
						transform = transform.Inverse;
					}
					useFilter = filterLimitBean.AddTransform(transform).GetUseFilter();
				}
				else
				{
					useFilter = filterLimitBean.GetUseFilter();
				}
				if (baseLinkDocumentResultBean.UseElement != null && useFilter.PassesFilter(baseLinkDocumentResultBean.UseElement))
				{
					list2.Add(baseLinkDocumentResultBean);
				}
			}
			if (this.m_bIfUseLevelLimit)
			{
				list2 = this.FilterBeanByLevelLimit(list2, this.m_dUseLevelLimit, this.m_dUesLevelLimitTolerance);
			}
			this.m_lstResultBean = list2;
		}

		private IList<Element> GetElementByFilter(Autodesk.Revit.DB.Document useDocument, object inputFilter)
		{
			if (inputFilter is FilterLimitBean)
			{
				ElementFilter useFilter = (inputFilter as FilterLimitBean).GetUseFilter();
				FilteredElementCollector filteredElementCollector = new FilteredElementCollector(useDocument);
				filteredElementCollector.WherePasses(useFilter);
				return filteredElementCollector.ToElements();
			}
			throw new ArgumentException();
		}

		private Level GetAElementLevel(Element input)
		{
			Level result = null;
			try
			{
				result = (input.Document.GetElement(input.LevelId) as Level);
			}
			catch (Exception)
			{
				result = null;
			}
			return result;
		}

		private Document m_useDoc;

		private List<BaseLinkDocumentResultBean> m_lstResultBean;

		private ElementFilter m_coreFilter;

		private ElementFilter m_getAllElementFilter = new LogicalOrFilter(new ElementIsElementTypeFilter(true), new ElementIsElementTypeFilter(false));

		private List<ElementFilter> m_lstViewLimitFilter = new List<ElementFilter>();

		private bool m_bIfUseLevelLimit;

		private double m_dUseLevelLimit;

		private double m_dUesLevelLimitTolerance;

		private CustomGetElementFilter m_GetElementFilterDelegate;
	}
}
